/**
 * 全局错误处理工具类
 */

interface ErrorInfo {
  code?: string | number;
  message: string;
  type: 'network' | 'server' | 'client' | 'validation' | 'permission' | 'unknown';
  details?: any;
  timestamp: number;
  url?: string;
  userAgent?: string;
}

interface ErrorHandlerOptions {
  showToast?: boolean;
  logToConsole?: boolean;
  reportToServer?: boolean;
  customHandler?: (error: ErrorInfo) => void;
}

class ErrorHandler {
  private static instance: ErrorHandler;
  private errorQueue: ErrorInfo[] = [];
  private maxQueueSize = 50;
  private reportUrl = '/api/errors/report';
  
  static getInstance(): ErrorHandler {
    if (!ErrorHandler.instance) {
      ErrorHandler.instance = new ErrorHandler();
    }
    return ErrorHandler.instance;
  }
  
  /**
   * 处理错误
   */
  handle(error: any, options: ErrorHandlerOptions = {}) {
    const errorInfo = this.parseError(error);
    
    // 添加到错误队列
    this.addToQueue(errorInfo);
    
    // 控制台日志
    if (options.logToConsole !== false) {
      this.logToConsole(errorInfo);
    }
    
    // 显示用户提示
    if (options.showToast !== false) {
      this.showUserFeedback(errorInfo);
    }
    
    // 上报服务器
    if (options.reportToServer) {
      this.reportToServer(errorInfo);
    }
    
    // 自定义处理
    if (options.customHandler) {
      options.customHandler(errorInfo);
    }
    
    return errorInfo;
  }
  
  /**
   * 解析错误信息
   */
  private parseError(error: any): ErrorInfo {
    const errorInfo: ErrorInfo = {
      message: '未知错误',
      type: 'unknown',
      timestamp: Date.now()
    };
    
    // 网络错误
    if (error.name === 'NetworkError' || error.code === 'NETWORK_ERROR') {
      errorInfo.type = 'network';
      errorInfo.message = '网络连接失败，请检查网络设置';
      errorInfo.code = error.code || 'NETWORK_ERROR';
    }
    // HTTP错误
    else if (error.status || error.statusCode) {
      const status = error.status || error.statusCode;
      errorInfo.code = status;
      
      if (status >= 400 && status < 500) {
        errorInfo.type = 'client';
        
        switch (status) {
          case 400:
            errorInfo.message = '请求参数错误';
            break;
          case 401:
            errorInfo.type = 'permission';
            errorInfo.message = '未授权访问，请先登录';
            break;
          case 403:
            errorInfo.type = 'permission';
            errorInfo.message = '访问被拒绝，权限不足';
            break;
          case 404:
            errorInfo.message = '请求的资源不存在';
            break;
          case 422:
            errorInfo.type = 'validation';
            errorInfo.message = '数据验证失败';
            break;
          default:
            errorInfo.message = `客户端错误 (${status})`;
        }
      } else if (status >= 500) {
        errorInfo.type = 'server';
        errorInfo.message = '服务器内部错误，请稍后重试';
      }
    }
    // JavaScript错误
    else if (error instanceof Error) {
      errorInfo.type = 'client';
      errorInfo.message = error.message;
      errorInfo.details = {
        name: error.name,
        stack: error.stack
      };
    }
    // 自定义错误对象
    else if (typeof error === 'object' && error.message) {
      errorInfo.message = error.message;
      errorInfo.code = error.code;
      errorInfo.type = error.type || 'unknown';
      errorInfo.details = error.details;
    }
    // 字符串错误
    else if (typeof error === 'string') {
      errorInfo.message = error;
    }
    
    // 添加环境信息
    errorInfo.url = getCurrentPageUrl();
    errorInfo.userAgent = getUserAgent();
    
    return errorInfo;
  }
  
  /**
   * 添加到错误队列
   */
  private addToQueue(errorInfo: ErrorInfo) {
    this.errorQueue.push(errorInfo);
    
    // 限制队列大小
    if (this.errorQueue.length > this.maxQueueSize) {
      this.errorQueue.shift();
    }
  }
  
  /**
   * 控制台日志
   */
  private logToConsole(errorInfo: ErrorInfo) {
    const logLevel = this.getLogLevel(errorInfo.type);
    const message = `[${errorInfo.type.toUpperCase()}] ${errorInfo.message}`;
    
    switch (logLevel) {
      case 'error':
        console.error(message, errorInfo);
        break;
      case 'warn':
        console.warn(message, errorInfo);
        break;
      default:
        console.log(message, errorInfo);
    }
  }
  
  /**
   * 获取日志级别
   */
  private getLogLevel(type: string): 'error' | 'warn' | 'info' {
    switch (type) {
      case 'server':
      case 'network':
        return 'error';
      case 'client':
      case 'validation':
        return 'warn';
      default:
        return 'info';
    }
  }
  
  /**
   * 显示用户反馈
   */
  private showUserFeedback(errorInfo: ErrorInfo) {
    const message = this.getUserFriendlyMessage(errorInfo);
    
    // 使用uni-app的提示
    if (typeof uni !== 'undefined') {
      uni.showToast({
        title: message,
        icon: 'none',
        duration: 3000
      });
    }
    // 或者使用自定义Toast组件
    else if ((window as any).showToast) {
      (window as any).showToast({
        type: this.getToastType(errorInfo.type),
        message: message
      });
    }
  }
  
  /**
   * 获取用户友好的错误消息
   */
  private getUserFriendlyMessage(errorInfo: ErrorInfo): string {
    // 根据错误类型返回用户友好的消息
    switch (errorInfo.type) {
      case 'network':
        return '网络连接异常，请检查网络后重试';
      case 'server':
        return '服务暂时不可用，请稍后重试';
      case 'permission':
        return '权限不足，请先登录';
      case 'validation':
        return '输入信息有误，请检查后重试';
      default:
        return errorInfo.message || '操作失败，请重试';
    }
  }
  
  /**
   * 获取Toast类型
   */
  private getToastType(errorType: string): string {
    switch (errorType) {
      case 'network':
      case 'server':
        return 'error';
      case 'validation':
      case 'permission':
        return 'warning';
      default:
        return 'info';
    }
  }
  
  /**
   * 上报到服务器
   */
  private async reportToServer(errorInfo: ErrorInfo) {
    try {
      // 过滤敏感信息
      const reportData = {
        ...errorInfo,
        userAgent: undefined, // 移除用户代理信息
        details: errorInfo.details ? JSON.stringify(errorInfo.details).substring(0, 1000) : undefined
      };
      
      // 发送错误报告
      await fetch(this.reportUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(reportData)
      });
    } catch (reportError) {
      console.warn('Failed to report error to server:', reportError);
    }
  }
  
  /**
   * 获取错误队列
   */
  getErrorQueue(): ErrorInfo[] {
    return [...this.errorQueue];
  }
  
  /**
   * 清空错误队列
   */
  clearErrorQueue() {
    this.errorQueue = [];
  }
  
  /**
   * 设置错误上报URL
   */
  setReportUrl(url: string) {
    this.reportUrl = url;
  }
}

/**
 * 获取当前页面URL
 */
function getCurrentPageUrl(): string {
  try {
    // uni-app环境
    if (typeof getCurrentPages === 'function') {
      const pages = getCurrentPages();
      const currentPage = pages[pages.length - 1];
      return currentPage ? currentPage.route || '' : '';
    }
    // Web环境
    else if (typeof window !== 'undefined' && window.location) {
      return window.location.href;
    }
  } catch (e) {
    // 忽略错误
  }
  return '';
}

/**
 * 获取用户代理信息
 */
function getUserAgent(): string {
  try {
    // uni-app环境
    if (typeof uni !== 'undefined' && uni.getSystemInfoSync) {
      const systemInfo = uni.getSystemInfoSync();
      return `${systemInfo.platform} ${systemInfo.system} ${systemInfo.version}`;
    }
    // Web环境
    else if (typeof navigator !== 'undefined') {
      return navigator.userAgent;
    }
  } catch (e) {
    // 忽略错误
  }
  return '';
}

// 导出单例实例
export const errorHandler = ErrorHandler.getInstance();

// 导出便捷方法
export const handleError = (error: any, options?: ErrorHandlerOptions) => {
  return errorHandler.handle(error, options);
};

// 导出类
export { ErrorHandler };

// 导出类型
export type { ErrorInfo, ErrorHandlerOptions };

// 导出全局错误处理器设置函数
export const setupGlobalErrorHandler = () => {
  // 已在文件底部自动设置
  console.log('Global error handler has been set up');
};

// 全局错误监听
if (typeof window !== 'undefined') {
  // 监听未捕获的JavaScript错误
  window.addEventListener('error', (event) => {
    handleError(event.error || event.message, {
      logToConsole: true,
      reportToServer: true
    });
  });
  
  // 监听未捕获的Promise错误
  window.addEventListener('unhandledrejection', (event) => {
    handleError(event.reason, {
      logToConsole: true,
      reportToServer: true
    });
  });
}